import {
  ConflictException,
  HttpStatus,
  Injectable,
  NotFoundException,
} from '@nestjs/common';
import { CreateMenuDto } from './dto/create-menu.dto';
import { UpdateMenuDto } from './dto/update-menu.dto';
import { Menu } from './entities/menu.entity';
import { Like, Repository } from 'typeorm';
import { InjectRepository } from '@nestjs/typeorm';
@Injectable()
export class MenuService {
  constructor(
    @InjectRepository(Menu) private readonly menuRepo: Repository<Menu>,
  ) { }
  async create(createMenuDto: CreateMenuDto) {
    const { name, path, icon, parentId, type } = createMenuDto;
    try {
      //保证name和path唯一
      if (await this.isMenuExists(name)) {
        throw new Error('Menu already exists');
      }
      if (await this.isPathExists(path)) {
        throw new Error('Path already exists');
      }
      const menu = new Menu();
      if (parentId) {
        const parentMenu = await this.menuRepo.findOne({
          where: { id: parentId },
        });
        if (!parentMenu) throw new NotFoundException(
          `Parent menu with id ${parentId} not found`,
        );
        menu.parentId = parentId;
        menu.fullPath = `${parentMenu.fullPath}/${path}`;
      } else {
        menu.fullPath = `/${path}`;
      }
      menu.name = name;
      menu.path = path;
      menu.type = type;
      if (icon) {
        menu.icon = icon;
      }

      return await this.menuRepo.save(menu);
    } catch (error) {
      throw new ConflictException({
        message: (error as Error)?.message,
        statusCode: HttpStatus.CONFLICT,
      });
    }
  }

  async getTreeMenu() {
    const menus = await this.menuRepo.find();
    const map: Record<number, any> = {};
    const roots: any[] = [];
    //创建映射表
    menus.forEach((menu) => {
      map[menu.id] = { ...menu, children: [] };
    });
    menus.forEach((menu) => {
      if (menu.parentId === null) {
        roots.push(map[menu.id]);
      } else {
        map[menu.parentId].children.push(map[menu.id]);
      }
    });

    return roots;
  }

  async getMenuList(queryMenuDto) {
    const { current = 1, pageSize = 20, name } = queryMenuDto;
    const [list, total] = await this.menuRepo.findAndCount({
      where: {
        ...(name && { name: Like(`%${name}%`) }),
      },
      skip: (current - 1) * pageSize,
      take: pageSize,
      order: { id: 'ASC' },
    });

    return {
      list,
      total,
      current,
      pageSize,
      name,
    };
  }

  findOne(id: number) {
    return `This action returns a #${id} menu`;
  }

  async update(id: number, updateMenuDto: UpdateMenuDto) {
    const { name, path, parentId, systemFlag } = updateMenuDto;
    const findOne = await this.menuRepo.findOne({ where: { id } });
    if (!findOne) throw new NotFoundException(`Menu with id ${id} not found`);
    if (parentId != undefined) {
      const parent = await this.menuRepo.findOne({
        where: { id: parentId },
      });
      if (!parent)
        throw new NotFoundException(
          `Parent menu with id ${parentId} not found`,
        );
    }

    const updateData = {
      name,
      path,
      parentId,
      systemFlag,
    };
    Object.assign(findOne, updateData);

    return await this.menuRepo.save(findOne);
  }

  async remove(id: number) {
    const menu = await this.menuRepo.findOne({ where: { id } });
    if (!menu) {
      throw new NotFoundException(`Menu with id ${id} not found`);
    }
    return this.menuRepo.remove(menu);
  }

  async isMenuExists(name: string) {
    return !!(await this.menuRepo.findOne({ where: { name } }));
  }

  async isPathExists(path: string) {
    return !!(await this.menuRepo.findOne({ where: { path } }));
  }
}
